#ifndef OPTHELPR_H
#define OPTHELPR_H

// following macros deal with ranking the hand and the counts[] array
//
#define JOKERRANK			15
#define ACERANK				14
#define KINGRANK			13
#define QUEENRANK			12
#define JACKRANK			11
#define COUNTNDX(rank)		((rank) - 2)		// card rank to counts[] index
#define RANKNDX(countndx)	((int32)((countndx)+2))	// counts[] to card rank
#define RANKPTR(p)			RANKNDX((p) - counts)
#define SUITNDX(suit)		(((suit) >> 4) - 1)
#define NDXSUIT(suitndx)	(((suitndx) + 1) << 4)

#define HAS(rank)			(counts[COUNTNDX(rank)])
#define HASACE()			HAS(ACERANK)
#define HASJOKER()			HAS(JOKERRANK)

#define HASSUIT(suit)		(suits[SUITNDX(suit)])

#define HPTR_JOKMGR()		hand->jokMgr()
#define HPTR_MGR()			hand->getMgr()
#define HPTR_GETSUIT(c)		HPTR_MGR()->getSuit(c)
#define HPTR_GETRANK(c)		HPTR_MGR()->getRank(c)
#define HPTR_ISJOKER(c)		HPTR_JOKMGR()->isJoker(c)
#define HPTR_GETSUIT_AT(i)	HPTR_GETSUIT(hand->getCardAt(i))
#define HPTR_GETRANK_AT(i)	HPTR_GETRANK(hand->getCardAt(i))
#define HPTR_ISJOKER_AT(i)	HPTR_ISJOKER(hand->getCardAt(i))

inline uint8*
hasMore_ofAKind_private(int32 n, uint8* buf, uint8* base)
{
	if (13 - (buf - base) > 0)
		return (uint8*)memchr(buf, n, 13 - (buf - base));

	return (uint8*)0;
}

inline uint8*
has_ofAKind_R(int32 n, uint8* buf, int32 bufsize)
{
	buf += bufsize - 1;

	while (bufsize-- > 0)
		if (*buf == n)
			return buf;
		else
			--buf;

	return (uint8*)0;
}

inline uint8*
skipZeros(uint8* buf, int32 bufsize)
{
	while (bufsize-- > 0)
		if (*buf)
			return buf;
		else
			++buf;

	return (uint8*)0;
}

inline uint8*
skipZeros_R(uint8* buf, int32 bufsize)
{
	buf += bufsize - 1;

	while (bufsize-- > 0)
		if (*buf)
			return buf;
		else
			--buf;

	return (uint8*)0;
}

#define has_ofAKind(n)			(uint8*)memchr(counts, (n), 13)
#define hasMore_ofAKind(n,p)	hasMore_ofAKind_private((n), (p), counts)
#define hasMore_ofAKind_R(n,p)	has_ofAKind_R((n),counts,(int32)((p)-counts+1))

#define skipMoreZeros(p)		skipZeros((p), (int32)(13 - ((p) - counts)))
#define skipMoreZeros_R(p)		skipZeros_R(counts, (int32)((p) - counts + 1))

inline int32
findMax(int32* index, uint8* buf, int32 bufsize)
{
	int32 result, i;

	if (buf && bufsize > 0)
	{
		result = buf[0];
		*index = 0;

		for (i = 1; i < 4; i++)
			if (buf[i] > result)
			{
				result = buf[i];
				*index = i;
			}
	}
	else
		result = *index = -1;

	return result;
}

inline bool8
twoCardsAtLeast(int32 toTestHi, int32 toTestLo, int32 minHi, int32 minLo)
{
	ASSERT(minHi <= ACERANK && minLo <= ACERANK);

	if (toTestHi == JOKERRANK)
		toTestHi = ACERANK;
	if (toTestLo == JOKERRANK)
		toTestLo = ACERANK;

	return (bool8)(toTestHi > minHi ||
		(toTestHi == minHi && toTestLo >= minLo));
}

inline bool8
twoCardsAtMost(int32 toTestHi, int32 toTestLo, int32 minHi, int32 minLo)
{
	ASSERT(minHi <= ACERANK && minLo <= ACERANK);

	if (toTestHi == JOKERRANK)
		toTestHi = ACERANK;
	if (toTestLo == JOKERRANK)
		toTestLo = ACERANK;

	return (bool8)(toTestHi < minHi ||
		(toTestHi == minHi && toTestLo <= minLo));
}

#endif
